﻿using System;
using Behaving;
using Behaving.Actions;
using Behaving.Composites;
using FluentAssertions;
using NUnit.Framework;

namespace Behaving.Tests
{
    [TestFixture]
    public class TestAddingBehaviours
    {
        protected int Total { get; set; }
        protected int Transactions { get; set; }

        [Test]
        public void Add_up_using_priority_selector()
        {
            Total = 563;
            Transactions = 0;
            BehaviourTree behaviourTree =
                new BehaviourTree(
                    new PriortySelector(
                        new ActionBehaviour(() => Total >= 100, () => ChangeTotal(-100)),
                        new ActionBehaviour(() => Total >= 10, () => ChangeTotal(-10)),
                        new ActionBehaviour(() => Total >= 1, () => ChangeTotal(-1))));

            int ticks = 0;
            while (ticks < 100 && behaviourTree.Tick() == RunningState.Success)
            {
                ticks++;
            }

            Total.Should().Be(0);
            Transactions.Should().Be(5 + 6 + 3);
        }

        [Test]
        public void Add_up_using_selector()
        {
            Total = 563;
            Transactions = 0;
            BehaviourTree behaviourTree =
                new BehaviourTree(
                    new Selector(
                        new ActionBehaviour(() => Total >= 100, () => ChangeTotal(-100)),
                        new ActionBehaviour(() => Total >= 10, () => ChangeTotal(-10)),
                        new ActionBehaviour(() => Total >= 1, () => ChangeTotal(-1))));

            int ticks = 0;
            while (ticks < 100 && behaviourTree.Tick() == RunningState.Success)
            {
                ticks++;
            }

            Total.Should().Be(0);
            Transactions.Should().Be(5 + 6 + 3);
        }

        [Test]
        public void Add_up_using_sequence()
        {
            Total = 563;
            Transactions = 0;
            BehaviourTree behaviourTree =
                new BehaviourTree(
                    new Sequence(
                        new ActionBehaviour(() => TryChangeTotal(-100)),
                        new ActionBehaviour(() => TryChangeTotal(-10)),
                        new ActionBehaviour(() => TryChangeTotal(-1))));

            int ticks = 0;
            while (ticks < 100 && behaviourTree.Tick() == RunningState.Running)
            {
                ticks++;
            }

            Total.Should().Be(0);
            Transactions.Should().Be(5 + 6 + 3);
        }

        [Test]
        public void Add_up_using_conditional()
        {
            Total = 563;
            Transactions = 0;
            BehaviourTree behaviourTree =
                new BehaviourTree(
                    new Conditional(
                        () => Total >= 100,
                        new ActionBehaviour(() => ChangeTotal(-100)),
                        new Conditional(
                            () => Total >= 10,
                            new ActionBehaviour(() => ChangeTotal(-10)),
                            new Conditional(
                                () => Total >= 1,
                                new ActionBehaviour(() => ChangeTotal(-1))))));

            int ticks = 0;
            while (ticks < 100 && behaviourTree.Tick() == RunningState.Success)
            {
                ticks++;
            }

            Total.Should().Be(0);
            Transactions.Should().Be(5 + 6 + 3);
        }

        [Test]
        public void Add_up_using_utility_selector()
        {
            Total = 563;
            Transactions = 0;
            BehaviourTree behaviourTree =
                new BehaviourTree(
                    new UtilitySelector(
                        new BehaviourUtility(b => Total >= 10 ? 10 : 0, new ActionBehaviour(() => ChangeTotal(-10))),
                        new BehaviourUtility(b => Total >= 100 ? 100 : 0, new ActionBehaviour(() => ChangeTotal(-100))),
                        new BehaviourUtility(b => Total >= 1 ? 1 : 0, new ActionBehaviour(() => ChangeTotal(-1)))));

            int ticks = 0;
            while (ticks < 100 && behaviourTree.Tick() == RunningState.Success)
            {
                ticks++;
            }

            Total.Should().Be(0);
            Transactions.Should().Be(5 + 6 + 3);
        }

        private void ChangeTotal(int amount)
        {
            Console.WriteLine("{0}: Adding {1} to make {2}", Total, amount, Total + amount);
            Total += amount;
            Transactions++;
        }

        private RunningState TryChangeTotal(int amount)
        {
            if (Total + amount >= 0)
            {
                Console.WriteLine("{0}: Adding {1} to make {2}", Total, amount, Total + amount);
                Total += amount;
                Transactions++;
                return RunningState.Running;
            }

            return RunningState.Success;
        }
    }
}